#include "ThreadCache.h"

void *ThreadCache::FetchMemoryFromCenterCache(size_t index, size_t size)
{
    // 调节申请块的数量，不会浪费太多内存，缓冲式申请
    int batchNum = std::min(_freelist[index].GetMaxBatch(), Size::NumMoveSize(size));
    if (_freelist[index].GetMaxBatch() == batchNum)
    {
        _freelist[index].GetMaxBatch() += 1;
        if (batchNum == 0)
        {
            batchNum = 1;
        }
    }

    // 向中心存储申请内存
    void *start = nullptr, *end = nullptr;
    size_t actualNum = CenterCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);

    assert(actualNum > 0);
    // 将多余的节点放在threadcache中，返回头一个即可。
    if (actualNum > 1)
    {
        assert(start != end);
        if (actualNum != 1)
            _freelist[index].pushRange(NextSite(start), end, actualNum - 1);
    }
    return start;
}

void *ThreadCache::Allocation(size_t size)
{
    int alignSize = Size().RoundUp(size);
    int index = Size().index(alignSize);
    if (_freelist[index].empty())
    {
        // cout << "通过上级中心申请空间" << endl;
        void *ptr = FetchMemoryFromCenterCache(index, alignSize);
        return ptr;
    }
    else
    {
        // cout << "通过自由链表申请空间" << endl;
        return _freelist[index].pop();
    }
}

void ThreadCache::Dealloction(void *ptr, size_t size)
{
    int alignSize = Size().RoundUp(size);
    int index = Size().index(alignSize);
    _freelist[index].push(ptr);

    size_t &MaxBatch = _freelist[index].GetMaxBatch();
    size_t &Size = _freelist[index].GetSize();

    if (Size == MaxBatch)
    {
        MaxBatch -= 1;
        void *start = nullptr, *end = nullptr;
        _freelist[index].popRange(start, end, Size);
        CenterCache::GetInstance()->RecycleToCenterStorage(start, index);
    }
}

void ThreadCache::Destroy()
{
    for (size_t index = 0; index < MAX_LIST; index++)
    {
        void *start = nullptr, *end = nullptr;
        size_t &Size = _freelist[index].GetSize();
        if(Size == 0) continue;
        _freelist[index].popRange(start, end, Size);
        CenterCache::GetInstance()->RecycleToCenterStorage(start, index);
    }
}
